home *** CD-ROM | disk | FTP | other *** search
- /*
- * rpcDispatch.c --
- *
- * The top level rpc dispatch routine. The dispatcher is responsible for
- * taking a packet from the packet transport level and passing it to the
- * delivery level of the correct process involved in the RPC. The
- * top-level dispatcher finds the protocol state for the client or server
- * receiving the message and calls the client or server specific dispatch
- * routine. This file also has the utility routine to copy a message from
- * the network module's buffers into the stub's buffers.
- *
- * Copyright 1985 Regents of the University of California
- * All rights reserved.
- */
-
- #ifndef lint
- static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/rpc/rpcDispatch.c,v 9.21 92/12/13 18:21:32 mgbaker Exp $ SPRITE (Berkeley)";
- #endif /* not lint */
-
- #include <sprite.h>
- #include <stdio.h>
- #include <bstring.h>
- #include <string.h>
- #include <dbg.h>
- #include <vm.h>
-
- #include <rpc.h>
- #include <rpcClient.h>
- #include <rpcServer.h>
- #include <rpcTrace.h>
- #include <rpcInt.h>
- #include <net.h>
-
- #include <recov.h>
-
- int ultra;
-
- /*
- * Our sprite ID. It is exported for general use by other modules.
- * This is set by a reverse arp transaction at boot time (see Rpc_Start),
- * or if that fails, by the rpc dispatcher who monitors the clientID field of
- * rpc reply messages (see RpcClientDispatch). Finally, if neither of
- * those hooks work, a diskfull node will set its address by looking at
- * the disk header (see FsAttachDisk).
- *
- * Important: servers won't respond to requests until their rpc_SpriteID is set.
- */
- int rpc_SpriteID = 0;
-
- /*
- * We stop handlling requests during a bad trap that causes us
- * to sync our disks. If that deadlocks we want to be sure that
- * the RPC system is off so we can't hang other machines.
- */
- extern int sys_ErrorSync;
-
- /*
- * While testing there may be many version mismatch errors. If
- * rpc_PrintMismatch is FALSE, then we only report a few of these errors
- * every once in a while.
- */
- int mismatchErrors = 0;
-
- /*
- * An array of bitmasks is kept for faster comparisions by the dispatcher.
- * Indexed by the total number of fragments in the packet, the array
- * contains a complete bitmask for that many fragments.
- */
- unsigned int rpcCompleteMask[17] = {
- 0x0000, 0x0001, 0x0003, 0x0007, 0x000F,
- 0x001F, 0x003F, 0x007F, 0x00FF,
- 0x01FF, 0x03FF, 0x07FF, 0x0FFF,
- 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
- /*
- * Forward declarations.
- */
- static Boolean ValidateClient _ARGS_((Net_Interface *interPtr, int protocol,
- Address headerPtr, RpcHdr *rpcHdrPtr));
- static void VersionMismatch _ARGS_((Net_Interface *interPtr, int protocol,
- Address headerPtr, RpcHdr *rpcHdrPtr, int packetLength));
-
-
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Rpc_Dispatch --
- *
- * This does some consistency checks on an incoming packet, finds the
- * protocol state for the packet (either client or server) and then
- * calls either the server or client dispatch routine.
- *
- * This still has a few ethernet specfich things that should be fixed.
- *
- * Results:
- * None.
- *
- * Side effects:
- * This may drop a packet if various consistency checks fail.
- *
- *----------------------------------------------------------------------
- */
- void
- Rpc_Dispatch(interPtr, protocol, headerPtr, rpcHdrAddr, packetLength)
- Net_Interface *interPtr; /* Network interface where we got the packet. */
- int protocol; /* Network protocol of packet. */
- Address headerPtr; /* Pointer to transport header. */
- Address rpcHdrAddr; /* RPC header of packet. */
- int packetLength; /* Size of RPC packet. */
- {
- register RpcHdr *rpcHdrPtr; /* RPC header of packet. */
- register int expectedLength;
- extern int ultra;
-
-
- if (ultra) {
- printf("In Rpc_Dispatch\n");
- }
- rpcHdrPtr = (RpcHdr *) rpcHdrAddr;
- if (packetLength < sizeof(RpcHdr)) {
- rpcCltStat.shorts++;
- printf("Rpc_Dispatch: SHORT packet, (%d) less than RpcHdr\n",
- packetLength, sizeof(RpcHdr));
- printf("Resetting network interface %s\n",
- interPtr->name);
- Net_Reset(interPtr);
- return;
- }
- if (rpcHdrPtr->version == rpc_SwappedVersion) {
- /*
- * Byte swap the packet header and the parameter block.
- */
- if (!RpcByteSwapInComing(rpcHdrPtr, packetLength)) {
- printf("Warning: Rpc_Dispatch failed byte-swap.\n");
- return;
- }
- } else if (rpcHdrPtr->version != rpc_NativeVersion) {
- /*
- * Keep a short list of hosts that aren't talking the
- * right version of RPC. Attempt to print out one message
- * about this per host, and then keep quiet.
- */
- VersionMismatch(interPtr, protocol, headerPtr, rpcHdrPtr, packetLength);
- return;
- }
- expectedLength = sizeof(RpcHdr) +
- rpcHdrPtr->paramSize +
- rpcHdrPtr->dataSize;
- if (packetLength < expectedLength) {
- rpcCltStat.shorts++;
- printf("Rpc_Dispatch: SHORT packet, (%d) not (%d), ",
- packetLength, expectedLength);
- printf("srv %d clt %d rpc %d\n", rpcHdrPtr->serverID,
- rpcHdrPtr->clientID, rpcHdrPtr->command);
- printf("Resetting network interface %s\n",
- interPtr->name);
- Net_Reset(interPtr);
- return;
- } else if (packetLength > expectedLength &&
- packetLength > interPtr->minBytes) {
- /*
- * Short messages (like acks and null replies)
- * get padded to minimum packet length. Other messages
- * get padded to 4 byte alignments.
- */
- rpcCltStat.longs++;
- if (packetLength > interPtr->maxBytes) {
- printf("Received oversized packet\n");
- printf("Resetting network interface\n");
- Net_Reset(interPtr);
- return;
- }
- }
-
- RPC_TRACE(rpcHdrPtr, RPC_INPUT, "Input");
-
- if (rpcHdrPtr->flags & RPC_SERVER) {
- register RpcServerState *srvPtr = (RpcServerState *) NIL;
- /*
- * Don't do anything if we don't know who we are. This occurs
- * at boot time if we get a request before doing reverse ARP.
- * Also, don't do anything in the middle of a panic. If a host
- * deadlocks trying to enter the debugger, then callback RPCs
- * from file servers should not also hang.
- */
- if (rpc_SpriteID == 0 || sys_ErrorSync) {
- return;
- }
- if (rpcHdrPtr->serverID != RPC_BROADCAST_SERVER_ID &&
- rpcHdrPtr->serverID != rpc_SpriteID) {
- /*
- * A bug, or the Intel chip is wack-o.
- */
- if (rpcHdrPtr->serverID > 0 &&
- rpcHdrPtr->serverID < NET_NUM_SPRITE_HOSTS) {
- char addrBuffer[128];
- Net_HdrDestString(interPtr->netType, protocol,headerPtr, 128,
- addrBuffer);
- printf("Warning: Rpc_Dispatch, wrong server ID %d\n",
- rpcHdrPtr->serverID);
- printf("\tRPC %d flags %x Client %d at address: %s\n",
- rpcHdrPtr->command, rpcHdrPtr->flags,
- rpcHdrPtr->clientID, addrBuffer);
-
- } else {
- printf("Rpc_Dispatch: junk serverID %d from client %d\n",
- rpcHdrPtr->serverID,
- rpcHdrPtr->clientID);
- }
- return;
- }
-
- rpcSrvStat.toServer++;
-
- /*
- * Verify or initialize the sprite host id for the client
- * (clientID) from the transport level source address.
- * This doesn't usually kick in unless the client can't do reverse arp.
- */
- if ( ! ValidateClient(interPtr, protocol, headerPtr, rpcHdrPtr)) {
- rpcSrvStat.invClient++;
- return;
- }
-
- /*
- * Save sender's requested interfragment delay.
- */
- rpcDelay[rpcHdrPtr->clientID] = rpcHdrPtr->delay;
- /*
- * Match the input message to a server process.
- */
- if (Recov_HoldForRecovery(rpcHdrPtr->clientID, rpcHdrPtr->command)) {
- srvPtr = (RpcServerState *) NIL;
- } else {
- srvPtr = RpcServerAlloc(rpcHdrPtr);
- }
- #ifdef NOTDEF
- srvPtr = RpcServerAlloc(rpcHdrPtr);
- #endif /* NOTDEF */
-
- if (srvPtr == (RpcServerState *)NIL) {
- /*
- * Is it okay to check this here?
- */
- if (rpcServiceEnabled) {
- rpcSrvStat.noAlloc++;
- if (rpcSendNegAcks) {
- RpcServerDispatch(srvPtr, rpcHdrPtr);
- }
- }
- } else {
- RpcServerDispatch(srvPtr, rpcHdrPtr);
- }
- } else {
- /*
- * Get the channel for the packet.
- */
- register RpcClientChannel *chanPtr;
-
- rpcCltStat.toClient++;
- if (rpcHdrPtr->channel < 0 ||
- rpcHdrPtr->channel >= rpcNumChannels) {
- rpcCltStat.badChannel++;
- printf("Rpc_Dispatch: bad channel %d from clt %d rpc %d",
- rpcHdrPtr->channel, rpcHdrPtr->clientID, rpcHdrPtr->command);
- printf("Resetting network interface %s\n", interPtr->name);
- Net_Reset(interPtr);
- } else {
- /*
- * Save sender's requested interfragment delay,
- * then dispatch to client process.
- */
- if (rpcHdrPtr->serverID < NET_NUM_SPRITE_HOSTS &&
- rpcHdrPtr->serverID > 0) {
- rpcDelay[rpcHdrPtr->serverID] = rpcHdrPtr->delay;
- }
- chanPtr = rpcChannelPtrPtr[rpcHdrPtr->channel];
- if (ultra) {
- printf("Calling RpcClientDispatch\n");
- }
- RpcClientDispatch(chanPtr, rpcHdrPtr);
- }
- }
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * RpcScatter --
- *
- * Copy the data in the network buffers into the buffers
- * specified by the scatter vector. This routine only works
- * on RPC messages. It knows the RPC packet format:
- * The Rpc header, which includes the sizes of the next two parts.
- * The parameter area.
- * The data area.
- * The scatter vector lengths of the last two parts are used
- * as maximum buffer sizes. The actual sizes of the parts is
- * taken from the rpc header. This is done because the RPC system
- * preallocates buffers which are large enough to handle any message.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The copy.
- *
- *----------------------------------------------------------------------
- */
- void
- RpcScatter(rpcHdrPtr, bufferPtr)
- register RpcHdr *rpcHdrPtr; /* The Rpc Header as it sits in the
- * network's buffer. The data follows
- * the header directly. */
- RpcBufferSet *bufferPtr; /* Specification of the buffers to
- * copy the message to. */
- {
- register Address netBufPtr; /* A pointer in to network buffer */
- register int length; /* Copying length */
- int destLength; /* length of destination buffers */
-
- netBufPtr = (Address)rpcHdrPtr;
-
- /*
- * Copy the RPC header.
- */
- length = bufferPtr->rpcHdrBuffer.length;
- bcopy(netBufPtr, bufferPtr->rpcHdrBuffer.bufAddr, length);
- netBufPtr += length;
- /*
- * Copy the parameter and data areas. Their sizes are in
- * the RPC header. Complain if either area is too large.
- */
- length = rpcHdrPtr->paramSize;
- if (length != 0) {
- destLength = bufferPtr->paramBuffer.length;
- if (length + rpcHdrPtr->paramOffset > destLength) {
- rpcCltStat.paramOverrun++;
- printf("RpcScatter: rpc %d param size + off (%d + %d) > (%d)\n",
- rpcHdrPtr->command, length, rpcHdrPtr->paramOffset,
- destLength);
- if (rpcHdrPtr->paramOffset < destLength) {
- length = destLength - rpcHdrPtr->paramOffset;
- } else {
- length = 0;
- }
- }
- bcopy(netBufPtr, bufferPtr->paramBuffer.bufAddr +
- rpcHdrPtr->paramOffset, length);
- netBufPtr += rpcHdrPtr->paramSize;
- }
- length = rpcHdrPtr->dataSize;
- if (length != 0) {
- destLength = bufferPtr->dataBuffer.length;
- if (length + rpcHdrPtr->dataOffset > destLength) {
- /*
- * The returned data is more than we expect. One reason for
- * this is that the Intel driver limits the size of the data area and
- * parameter area to be 0, or to be greater than 12 bytes because
- * of the Intel DMA hardware.
- */
- rpcCltStat.dataOverrun++;
- if (rpcHdrPtr->dataOffset < destLength) {
- length = destLength - rpcHdrPtr->dataOffset;
- } else {
- length = 0;
- }
- }
- bcopy(netBufPtr, bufferPtr->dataBuffer.bufAddr + rpcHdrPtr->dataOffset,
- length);
- }
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * ValidateClient --
- *
- * Check the clientID field of an incoming Rpc request. Invalid ID's
- * are screened out, and the special clientID of zero is overwritten
- * with the client's true sprite ID. This is done by looking the
- * client's physical address up in a table with Net_AddrToID. This
- * true sprite ID is propogated back to clients so they can determine
- * their own sprite ID. This should be replaced by the use of
- * Reverse Arp on clients at boot time.
- *
- * Results:
- * FALSE if clientID is invalid or the physical address of the client
- * isn't in the table. TRUE otherwise - this gurantees a valid
- * clientID in the RpcHdr.
- *
- * Side effects:
- * Muck with the header so that subsequent users of the RpcHdr see a
- * valid clientID field.
- *
- *----------------------------------------------------------------------
- */
- static Boolean
- ValidateClient(interPtr, protocol, headerPtr, rpcHdrPtr)
- Net_Interface *interPtr; /* Network interface. */
- int protocol; /* Network protocol of packet. */
- Address headerPtr; /* Transport header. */
- RpcHdr *rpcHdrPtr;
- {
- register int clientID;
- register Boolean result = FALSE;
-
- clientID = rpcHdrPtr->clientID;
-
- if (clientID > 0 && clientID < NET_NUM_SPRITE_HOSTS) {
- /*
- * A potentially valid clientID. We don't need to
- * save the client's transport address because the
- * we can get that from the saved request message.
- */
- result = TRUE;
- } else if (clientID == 0) {
- /*
- * Look client's transport address up in our in core host table.
- */
- clientID = Net_HdrToID(interPtr->netType, protocol, headerPtr);
- printf("Warning: RpcValidateClient had to set clientID %d\n", clientID);
- if (clientID < 0) {
- char addrBuffer[128];
- /*
- * Should invoke Reverse ARP to find out the Sprite ID.
- */
- Net_HdrDestString(interPtr->netType, protocol, headerPtr, 128,
- addrBuffer);
- printf("Client at unknown address: %s\n", addrBuffer);
- result = FALSE;
- } else {
- rpcHdrPtr->clientID = clientID;
- result = TRUE;
- }
- } else {
- result = FALSE;
- printf("Invalid Client Sprite ID (%d)\n", clientID);
- }
- return(result);
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * VersionMismatch --
- *
- * This is called upon reciept of a packet with a bad RPC version
- * number. This routine keeps a short list of offending hosts,
- * and will print out a warning about each one it encounters.
- *
- * Results:
- * None.
- *
- * Side effects:
- * This adds items to its versionList.
- *
- *----------------------------------------------------------------------
- */
- static int numVersions = 0;
-
- #define ADDR_LEN 40
- typedef struct {
- Net_Interface *interPtr; /* Network interface. */
- int protocol; /* The packet protocol. */
- int count; /* Count of mismatches */
- char sourceAddr[ADDR_LEN]; /* Storage for source addr string */
- } VersionRecord;
-
- #define NUM_VERSIONS 4
- static VersionRecord versionList[NUM_VERSIONS];
-
- static void
- VersionMismatch(interPtr, protocol, headerPtr, rpcHdrPtr, packetLength)
- Net_Interface *interPtr; /* Network interface. */
- int protocol; /* Network protocol of packet. */
- Address headerPtr; /* Pointer to transport header. */
- RpcHdr *rpcHdrPtr; /* RPC header of packet. */
- int packetLength; /* Size of RPC packet. */
- {
- char addrBuffer[ADDR_LEN];
- int i;
- char *type;
- char *proto;
-
- /*
- * Get a string value for the sender of the packet and see if
- * we've already gotten a bad packet from this host.
- */
- Net_HdrDestString(interPtr->netType, protocol, headerPtr, ADDR_LEN,
- addrBuffer);
-
- for (i=0 ; i<numVersions ; i++) {
- if (strcmp(versionList[i].sourceAddr, addrBuffer) == 0) {
- versionList[i].count++;
- return;
- }
- }
- if (numVersions >= NUM_VERSIONS) {
- /*
- * Bail out if we don't have room in the versionList.
- * Alternatively we could replace an entry in the versionList.
- */
- return;
- }
-
- switch(interPtr->netType) {
- case NET_NETWORK_ETHER:
- type = "ether";
- break;
- default:
- type = "unknown network type";
- break;
- }
- switch(protocol) {
- case NET_PROTO_RAW:
- proto = "raw";
- break;
- case NET_PROTO_INET:
- proto = "inet";
- break;
- default:
- proto = "unknown network protocol";
- break;
- }
- printf("RPC Version mismatch: %x not %x from %s %s %s",
- rpcHdrPtr->version, rpc_NativeVersion, type, proto, addrBuffer);
- if (rpcHdrPtr->clientID > 0 && rpcHdrPtr->clientID < NET_NUM_SPRITE_HOSTS) {
- printf(" clientID %d\n", rpcHdrPtr->clientID);
- } else {
- printf("\n");
- }
- versionList[numVersions].count = 1;
- versionList[numVersions].protocol = protocol;
- versionList[numVersions].interPtr = interPtr;
- (void) strncpy(versionList[numVersions].sourceAddr, addrBuffer, ADDR_LEN);
- numVersions++;
-
- return;
- }
-